package com.irssproject.app.web.action.recommendations;

import com.irssproject.app.entitats.*;
import com.irssproject.app.entitats.recommendations.UserClustersRecommendation;
import com.irssproject.app.entitats.recommendations.WebUser;
import com.irssproject.app.service.main.iface.UsersService;
import com.irssproject.app.service.recommendations.iface.RecommendationsService;
import com.irssproject.app.utils.Constants;
import com.irssproject.app.utils.Utils;
import com.irssproject.app.web.action.JSONWrappers.ReadingProfileJSON;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

public class RecommendationsAction extends ActionSupport {

    public RecommendationsAction(UsersService usuariService, RecommendationsService recommendationsService) {
        this.usuariService = usuariService;
        this.recommendationsService = recommendationsService;
    }
    private static final long serialVersionUID = 1L;
    private static final Logger logger = Logger.getLogger(RecommendationsAction.class.getName());
    private RecommendationsService recommendationsService;
    private UsersService usuariService;
    private String nomEtiqueta;
    private List<UserClustersRecommendation> topClustersList;
    private List<Label> llistaGlobalEtiquetes;
    private List<Feed> llistaGlobalFeeds;
    private List<Item> llistaGlobalItems;
    private List<ReadingProfileJSON> perfilsCoincidents;
    private List<WebUser> userRecommendedList;
    private List<WebUser> fillUserRecommendedList;
    private List<UserClustersRecommendation> matchingClustersList;
    private List<UserClustersRecommendation> fillMatchingClustersList;
    private String usuari;
    //can be feed Id or cluster Id
    private String selectedId;
    // for the personalized recommendation
    private String selectedConceptId;
    private String selectedConceptName;
    private String selectedUserId;
    private String itemsIdAlreadyShowed = null;
    private String usersIdAlreadyShowed = null;
    private String topicsIdAlreadyShowed = null;
    private List<Item> persItemsList;
    private List<Item> fillPersItemsList;
    private String errorMessage;

    public String getErrorMessage() {
        return errorMessage;
    }

    public void setErrorMessage(String errorMessage) {
        this.errorMessage = errorMessage;
    }
    private String topic;

    /**
     * *******************************************************
     */
    /**
     * *****************Top Recommendations*******************
     */
    /**
     * *******************************************************
     */
    public String getTopClusters() {
        Map session = ActionContext.getContext().getSession();
        User connectedUser = ((User) session.get(Constants.SESSIO_USUARI_AUTENTICAT));

        topClustersList = recommendationsService.getTopClusters(connectedUser);

        setTopClustersList(topClustersList);

        return SUCCESS;
    }

    public String getTopFeeds() {

        Map session = ActionContext.getContext().getSession();
        User connectedUser = ((User) session.get(Constants.SESSIO_USUARI_AUTENTICAT));

        llistaGlobalFeeds = recommendationsService.getTopFeeds(connectedUser);

        setLlistaGlobalFeeds(llistaGlobalFeeds);

        return SUCCESS;
    }

    public String getTopItems() {

        Map session = ActionContext.getContext().getSession();
        User connectedUser = ((User) session.get(Constants.SESSIO_USUARI_AUTENTICAT));

        llistaGlobalItems = recommendationsService.getTopItems(connectedUser);

        setLlistaGlobalItems(llistaGlobalItems);

        return SUCCESS;
    }

    public String fillTopItems() {
        //userId
        //conceptId
        //itemsIdAlreadyShowed[]
        Map session = ActionContext.getContext().getSession();
        User connectedUser = ((User) session.get(Constants.SESSIO_USUARI_AUTENTICAT));

        String[] items = Utils.jsonStringToArray(itemsIdAlreadyShowed);
        llistaGlobalItems = recommendationsService.fillTopItems(connectedUser, items);

        return SUCCESS;

    }

    public String getTopItemsByCluster() throws Exception {

        Map session = ActionContext.getContext().getSession();
        User connectedUser = ((User) session.get(Constants.SESSIO_USUARI_AUTENTICAT));

        Long idConcept = 0L;
        if (selectedId != null && !selectedId.isEmpty()) {
            try {
                idConcept = Long.parseLong(selectedId);
            } catch (NumberFormatException e) {
                logger.severe(e.getMessage());
            }

            llistaGlobalItems = recommendationsService.getTopItemsByTopic(connectedUser, idConcept);

        }
        return SUCCESS;
    }

    /**
     * gets items from the feed specified to show after items obtained with
     * getPersItemsByCluster
     */
    public String fillTopItemsByCluster() {
        //userId
        //conceptId
        //itemsIdAlreadyShowed[]
        Map session = ActionContext.getContext().getSession();
        User connectedUser = ((User) session.get(Constants.SESSIO_USUARI_AUTENTICAT));

        Long conceptId = 0L;
        String[] items = Utils.jsonStringToArray(itemsIdAlreadyShowed);
        if (selectedId != null && !selectedId.isEmpty()) {
            try {
                conceptId = Long.parseLong(selectedId);
            } catch (NumberFormatException e) {
                logger.severe(e.getMessage());
            }

            llistaGlobalItems = recommendationsService.fillTopItemsByCluster(connectedUser, conceptId, items);

        }
        return SUCCESS;

    }

    public String getTopItemsByFeed() {

        Map session = ActionContext.getContext().getSession();
        User connectedUser = ((User) session.get(Constants.SESSIO_USUARI_AUTENTICAT));

        long idFeed = 0;
        if (selectedId != null && !selectedId.isEmpty()) {
            try {
                idFeed = Long.parseLong(selectedId);
            } catch (NumberFormatException e) {
                logger.severe(e.getMessage());
            }

            llistaGlobalItems = recommendationsService.getTopItemsByFeed(connectedUser, idFeed);
        }

        return SUCCESS;
    }

    /**
     * gets items from the feed specified to show after items obtained with
     * getPersItemsByCluster
     */
    public String fillTopItemsByFeed() {
        //userId
        //conceptId
        //itemsIdAlreadyShowed[]
        Map session = ActionContext.getContext().getSession();
        User connectedUser = ((User) session.get(Constants.SESSIO_USUARI_AUTENTICAT));

        Long feedId = 0L;
        String[] items = Utils.jsonStringToArray(itemsIdAlreadyShowed);
        if (selectedId != null && !selectedId.isEmpty()) {
            try {
                feedId = Long.parseLong(selectedId);
            } catch (NumberFormatException e) {
                logger.severe(e.getMessage());
            }

            llistaGlobalItems = recommendationsService.fillTopItemsByFeed(connectedUser, feedId, items);

        }
        return SUCCESS;

    }

    /**
     * *******************************************************
     */
    /**
     * *************Personalized Recommendations**************
     */
    /**
     * *******************************************************
     */
    /**
     * Generate personalized recommendation of users sharing interests with the
     * connected user
     */
    public String getNeighbors() throws Exception {

        Map session = ActionContext.getContext().getSession();
        User connectedUser = ((User) session.get(Constants.SESSIO_USUARI_AUTENTICAT));

        logger.log(Level.INFO, "Generating recommendations for user {0}", connectedUser.getLogin());
        List<User> userList = recommendationsService.getNeighbors(connectedUser);
        userRecommendedList = new ArrayList<WebUser>();
        for (User user : userList) {
            logger.log(Level.INFO, "neighbor calculated --> {0}", user.getName());
            userRecommendedList.add(new WebUser(user));
        }
        return SUCCESS;
    }

    public String fillNeighbors() throws Exception {

        Map session = ActionContext.getContext().getSession();
        User connectedUser = ((User) session.get(Constants.SESSIO_USUARI_AUTENTICAT));

        logger.log(Level.INFO, "Filling recommendations for user {0}", connectedUser.getLogin());
        String[] items = Utils.jsonStringToArray(usersIdAlreadyShowed);

        List<User> userList = recommendationsService.fillNeighbors(connectedUser, items);
        fillUserRecommendedList = new ArrayList<WebUser>();
        for (User user : userList) {
            logger.log(Level.INFO, "neighbor calculated --> {0}", user.getName());
            fillUserRecommendedList.add(new WebUser(user));
        }
        return SUCCESS;
    }

    public String getClusters() {
        try {
            Map session = ActionContext.getContext().getSession();
            User connectedUser = (User) session.get(Constants.SESSIO_USUARI_AUTENTICAT);
            logger.log(Level.INFO, "Generating clusters");

            matchingClustersList = recommendationsService.getClusters(connectedUser);
            for (UserClustersRecommendation uclr : matchingClustersList) {
                logger.log(Level.INFO, "cluster generated --> {0}", uclr.getValueConcept());
            }

            return SUCCESS;
        } catch (Exception ex) {
            Logger.getLogger(RecommendationsAction.class.getName()).log(Level.SEVERE, null, ex);
            return ERROR;
        }
    }

    public String fillClusters() throws Exception {

        Map session = ActionContext.getContext().getSession();
        User connectedUser = ((User) session.get(Constants.SESSIO_USUARI_AUTENTICAT));

        String[] items = Utils.jsonStringToArray(topicsIdAlreadyShowed);
        logger.log(Level.INFO, "Filling clusters");

        fillMatchingClustersList = recommendationsService.fillClusters(connectedUser, items);
        for (UserClustersRecommendation uclr : fillMatchingClustersList) {
            logger.log(Level.INFO, "cluster generated --> {0}", uclr.getValueConcept());
        }
        return SUCCESS;
    }

    public String getMatchingClusters() {

        Map session = ActionContext.getContext().getSession();
        User connectedUser = ((User) session.get(Constants.SESSIO_USUARI_AUTENTICAT));
        User recommendedUser = usuariService.getUserByLogin(usuari);
        if (recommendedUser != null) {
            logger.log(Level.INFO, "Calculating related topics with user {0}", recommendedUser.getLogin());
            matchingClustersList = recommendationsService.getMatchingClusters(connectedUser, recommendedUser);
        }
        return SUCCESS;
    }

    public String fillMatchingClusters() throws Exception {

        Map session = ActionContext.getContext().getSession();
        User connectedUser = ((User) session.get(Constants.SESSIO_USUARI_AUTENTICAT));
        User recommendedUser = usuariService.getUserByLogin(usuari);

        String[] items = Utils.jsonStringToArray(topicsIdAlreadyShowed);

        if (recommendedUser != null) {
            logger.log(Level.INFO, "Filling related topics with user {0}", recommendedUser.getLogin());
            fillMatchingClustersList = recommendationsService.fillMatchingClusters(connectedUser, recommendedUser, items);
        }
        return SUCCESS;
    }

    public String getPersItemsByCluster() throws Exception {
        Long conceptId = 0L;
        Long userId = 0L;
        if (selectedConceptId != null && !selectedConceptId.isEmpty()
                && selectedUserId != null && !selectedUserId.isEmpty()) {
            try {
                conceptId = Long.parseLong(selectedConceptId);
                userId = Long.parseLong(selectedUserId);
            } catch (NumberFormatException e) {
                logger.severe(e.getMessage());
            }

            persItemsList = recommendationsService.getPersItemsByCluster(conceptId, userId);
        }
        return SUCCESS;
    }

    /**
     * gets items from the feed specified to show after items obtained with
     * getPersItemsByCluster
     */
    public String fillPersItemsByCluster() {
        //userId
        //conceptId
        //itemsIdAlreadyShowed[]
        Long conceptId = 0L;
        Long userId = 0L;
        String[] items = Utils.jsonStringToArray(itemsIdAlreadyShowed);
        if (selectedConceptId != null && !selectedConceptId.isEmpty()
                && selectedUserId != null && !selectedUserId.isEmpty()) {
            try {
                conceptId = Long.parseLong(selectedConceptId);
                userId = Long.parseLong(selectedUserId);
            } catch (NumberFormatException e) {
                logger.severe(e.getMessage());
            }

            fillPersItemsList = recommendationsService.fillPersItemsByCluster(conceptId, userId, items);

        }
        return SUCCESS;

    }

    public String createUserSubscription() throws Exception {

        try {
            Map session = ActionContext.getContext().getSession();
            User connectedUser = ((User) session.get(Constants.SESSIO_USUARI_AUTENTICAT));
            User userToSubs = usuariService.getUserByLogin(usuari.trim());
            recommendationsService.createUserSubscription(connectedUser, userToSubs);
        } catch (Exception e) {
            if (e.getMessage().equals(Constants.USER_ALREADY_SUBSCRIBED)) {
                errorMessage = "You already have a relationship with this user. It won't be added.";
            } else {
                errorMessage = "There was an unexpected error. Try again.";
            }
        }
        return SUCCESS;
    }

    public String createTopicSubscription() throws Exception {
        try {
            Map session = ActionContext.getContext().getSession();
            User connectedUser = ((User) session.get(Constants.SESSIO_USUARI_AUTENTICAT));
            Long conceptId;
            if (selectedConceptId != null && !selectedConceptId.isEmpty()) {
                try {
                    conceptId = Long.parseLong(selectedConceptId);
                    recommendationsService.createTopicSubscription(connectedUser, conceptId);
                } catch (NumberFormatException e) {
                    logger.severe(e.getMessage());
                }
            } else if (selectedConceptName != null && !selectedConceptName.isEmpty()) {
                recommendationsService.createTopicSubscription(connectedUser, selectedConceptName);
            }
        } catch (Exception e) {
            if (e.getMessage().equals(Constants.TOPIC_ALREADY_SUBSCRIBED)) {
                errorMessage = "You already have subscribed to this topic. It won't be added.";
            } else {
                errorMessage = "There was an unexpected error. Try again.";
            }
        }
        return SUCCESS;
    }

    public String getItemsByTopic() {

        if (topic != null && !topic.isEmpty()) {
            Map session = ActionContext.getContext().getSession();
            User connectedUser = ((User) session.get(Constants.SESSIO_USUARI_AUTENTICAT));

            System.out.println("---> " + topic);
            persItemsList = recommendationsService.getTopItemsByTopic(connectedUser, topic);
        }
        return SUCCESS;
    }

    /**
     * *******************************************************
     */
    /**
     * ******************Getters and setters******************
     */
    /**
     * *******************************************************
     */
    public void setUsersService(UsersService usuariService) {
        this.usuariService = usuariService;
    }

    public void setRecommendationsService(RecommendationsService recommendationsService) {
        this.recommendationsService = recommendationsService;
    }

    public List<WebUser> getUserRecommendedList() {
        return userRecommendedList;
    }

    public void setUserRecommendedList(List<WebUser> userRecommendedList) {
        this.userRecommendedList = userRecommendedList;
    }

    public List<UserClustersRecommendation> getMatchingClustersList() {
        return matchingClustersList;
    }

    public void setMatchingClustersList(List<UserClustersRecommendation> mcList) {
        this.matchingClustersList = mcList;
    }

    public String getUsuari() {
        return usuari;
    }

    public void setUsuari(String usuari) {
        this.usuari = usuari;
    }

    public List<ReadingProfileJSON> getPerfilsCoincidents() {
        return perfilsCoincidents;
    }

    public void setPerfilsCoincidents(List<ReadingProfileJSON> perfilsCoincidents) {
        this.perfilsCoincidents = perfilsCoincidents;
    }

    public String getNomEtiqueta() {
        return nomEtiqueta;
    }

    public void setNomEtiqueta(String nomEtiqueta) {
        this.nomEtiqueta = nomEtiqueta;
    }

    public List<UserClustersRecommendation> getTopClustersList() {
        return topClustersList;
    }

    public void setTopClustersList(List<UserClustersRecommendation> topClustersList) {
        this.topClustersList = topClustersList;
    }

    public List<Label> getLlistaGlobalEtiquetes() {
        return llistaGlobalEtiquetes;
    }

    public void setLlistaGlobalEtiquetes(List<Label> llistaGlobalEtiquetes) {
        this.llistaGlobalEtiquetes = llistaGlobalEtiquetes;
    }

    public List<Feed> getLlistaGlobalFeeds() {
        return llistaGlobalFeeds;
    }

    public void setLlistaGlobalFeeds(List<Feed> llistaGlobalFeeds) {
        this.llistaGlobalFeeds = llistaGlobalFeeds;
    }

    public List<Item> getLlistaGlobalItems() {
        return llistaGlobalItems;
    }

    public void setLlistaGlobalItems(List<Item> llistaGlobalItems) {
        this.llistaGlobalItems = llistaGlobalItems;
    }

    public String getSelectedId() {
        return selectedId;
    }

    public void setSelectedId(String selectedId) {
        this.selectedId = selectedId;
    }

    public String getSelectedConceptId() {
        return selectedConceptId;
    }

    public void setSelectedConceptId(String selectedConceptId) {
        this.selectedConceptId = selectedConceptId;
    }

    public String getSelectedConceptName() {
        return selectedConceptName;
    }

    public void setSelectedConceptName(String selectedConceptName) {
        this.selectedConceptName = selectedConceptName;
    }

    public String getSelectedUserId() {
        return selectedUserId;
    }

    public void setSelectedUserId(String selectedUserId) {
        this.selectedUserId = selectedUserId;
    }

    public String getItemsIdAlreadyShowed() {
        return itemsIdAlreadyShowed;
    }

    public void setItemsIdAlreadyShowed(String itemsIdAlreadyShowed) {
        this.itemsIdAlreadyShowed = itemsIdAlreadyShowed;
    }

    public String getTopicsIdAlreadyShowed() {
        return topicsIdAlreadyShowed;
    }

    public void setTopicsIdAlreadyShowed(String topicsIdAlreadyShowed) {
        this.topicsIdAlreadyShowed = topicsIdAlreadyShowed;
    }

    public String getUsersIdAlreadyShowed() {
        return usersIdAlreadyShowed;
    }

    public void setUsersIdAlreadyShowed(String usersIdAlreadyShowed) {
        this.usersIdAlreadyShowed = usersIdAlreadyShowed;
    }

    public List<Item> getPersItemsList() {
        return persItemsList;
    }

    public void setPersItemsList(List<Item> persItemsList) {
        this.persItemsList = persItemsList;
    }

    public List<Item> getFillPersItemsList() {
        return fillPersItemsList;
    }

    public void setFillPersItemsList(List<Item> fillPersItemsList) {
        this.fillPersItemsList = fillPersItemsList;
    }

    public List<WebUser> getFillUserRecommendedList() {
        return fillUserRecommendedList;
    }

    public void setFillUserRecommendedList(List<WebUser> fillUserRecommendedList) {
        this.fillUserRecommendedList = fillUserRecommendedList;
    }

    public List<UserClustersRecommendation> getFillMatchingClustersList() {
        return fillMatchingClustersList;
    }

    public void setFillMatchingClustersList(List<UserClustersRecommendation> fillMatchingClustersList) {
        this.fillMatchingClustersList = fillMatchingClustersList;
    }

    public String getTopic() {
        return topic;
    }

    public void setTopic(String topic) {
        this.topic = topic;
    }
}
